﻿#include "bluetoothCtrl.h"
#include "BluetoothDeviceModel.h"
#include "LowEnergyInfoModel.h"
#include <QtCore/QTimer>
#include <QtCore/QDebug>


BluetoothCtrl::BluetoothCtrl(QObject *parent) : QObject(parent)
{
    // power on local bluetooth
    mLocalBluetooth.powerOn();
    //qDebug() << "hostMode:" << mLocalBluetooth.hostMode();
    mLocalBluetooth.setHostMode(QBluetoothLocalDevice::HostConnectable);
    //qDebug() << "localBluetooth hostMode:" << mLocalBluetooth.hostMode()
    //         << "name:" << mLocalBluetooth.name()
    //         << "address:" << mLocalBluetooth.address()
    //            ;

    connect(&mLocalBluetooth, SIGNAL(hostModeStateChanged(QBluetoothLocalDevice::HostMode)), this, SLOT(localBluetoothHostModeStateChanged(QBluetoothLocalDevice::HostMode)));
    connect(&mLocalBluetooth, SIGNAL(deviceConnected(const QBluetoothAddress &)), this, SLOT(localBluetoothDeviceConnected(const QBluetoothAddress &)));
    connect(&mLocalBluetooth, SIGNAL(deviceDisconnected(const QBluetoothAddress&)), this, SLOT(localBluetoothDeviceDisconnected(const QBluetoothAddress&)));
    connect(&mLocalBluetooth, SIGNAL(pairingFinished(const QBluetoothAddress &, QBluetoothLocalDevice::Pairing)), this, SLOT(localBluetoothPairingFinished(const QBluetoothAddress &, QBluetoothLocalDevice::Pairing)));
    connect(&mLocalBluetooth, SIGNAL(pairingDisplayPinCode(const QBluetoothAddress &, QString)), this, SLOT(localBluetoothPairingDisplayPinCode(const QBluetoothAddress &, QString)));
    connect(&mLocalBluetooth, SIGNAL(pairingDisplayConfirmation(const QBluetoothAddress &, QString)), this, SLOT(localBluetoothPairingDisplayConfirmation(const QBluetoothAddress &, QString)));
    connect(&mLocalBluetooth, SIGNAL(error(QBluetoothLocalDevice::Error)), this, SLOT(localBluetoothError(QBluetoothLocalDevice::Error)));
    //
    connect(&mDeviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this, &BluetoothCtrl::deviceDiscoveryAgentDeviceDiscovered);
    connect(&mDeviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceUpdated, this, &BluetoothCtrl::deviceDiscoveryAgentDeviceUpdated);
    connect(&mDeviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, &BluetoothCtrl::deviceDiscoveryAgentDiscoveredFinished);
    connect(&mDeviceDiscoveryAgent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)), this, SLOT(deviceDiscoveryAgentError(QBluetoothDeviceDiscoveryAgent::Error)));
    connect(&mDeviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::canceled, this, &BluetoothCtrl::deviceDiscoveryAgentCanceled);
    //qDebug() << "lowEnergyDiscoveryTimeout:" << mDeviceDiscoveryAgent.lowEnergyDiscoveryTimeout();    // lowEnergyDiscoveryTimeout: 25000 (默认)
    //qDebug() << "supportedDiscoveryMethods:" << mDeviceDiscoveryAgent.supportedDiscoveryMethods();      // supportedDiscoveryMethods: QFlags<QBluetoothDeviceDiscoveryAgent::DiscoveryMethod>(ClassicMethod|LowEnergyMethod)
    mDeviceDiscoveryAgent.setLowEnergyDiscoveryTimeout(50000);
    //
    connect(&mServiceDiscoveryAgent, &QBluetoothServiceDiscoveryAgent::serviceDiscovered, this, &BluetoothCtrl::serviceDiscovered);
    connect(&mServiceDiscoveryAgent, &QBluetoothServiceDiscoveryAgent::finished, this, &BluetoothCtrl::serviceDiscoveryFinished);
    connect(&mServiceDiscoveryAgent, SIGNAL(error(QBluetoothServiceDiscoveryAgent::Error)), this, SLOT(serviceError(QBluetoothServiceDiscoveryAgent::Error)));
    connect(&mServiceDiscoveryAgent, &QBluetoothServiceDiscoveryAgent::canceled, this, &BluetoothCtrl::serviceDiscoveryCanceled);

}

BluetoothCtrl *BluetoothCtrl::singleton()
{
    static BluetoothCtrl * singleton = new BluetoothCtrl();
    return singleton;
}

// /////////////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////////////
void BluetoothCtrl::localBluetoothHostModeStateChanged(QBluetoothLocalDevice::HostMode state)
{
    qDebug() << "localBluetoothHostModeStateChanged: " << state;
}
void BluetoothCtrl::localBluetoothDeviceConnected(const QBluetoothAddress &address)
{
    emit signalBluetoothState(BluetoothCtrl::BluetoothState_localConnected);
    qDebug() << "localBluetoothDeviceConnected: " << address;
}

void BluetoothCtrl::localBluetoothDeviceDisconnected(const QBluetoothAddress &address)
{
    emit signalBluetoothState(BluetoothCtrl::BluetoothState_localDisconnected);
    qDebug() << "localBluetoothDeviceDisconnected: " << address;
}

void BluetoothCtrl::localBluetoothPairingFinished(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing)
{
    qDebug() << "localBluetoothPairingFinished: " << address << " " << pairing;
}

void BluetoothCtrl::localBluetoothPairingDisplayPinCode(const QBluetoothAddress &address, QString pin)
{
    qDebug() << "localBluetoothPairingDisplayPinCode:  " << address << " " << pin;
}

void BluetoothCtrl::localBluetoothPairingDisplayConfirmation(const QBluetoothAddress &address, QString pin)
{
    qDebug() << "localBluetoothPairingDisplayConfirmation:  " << address << " " << pin;
    mLocalBluetooth.pairingConfirmation(true);
}

void BluetoothCtrl::localBluetoothError(QBluetoothLocalDevice::Error error)
{
    qDebug() << "localBluetoothError: " << error;
    switch (error) {
    case QBluetoothLocalDevice::NoError: break;
    case QBluetoothLocalDevice::PairingError:
        emit signalBluetoothState(BluetoothState_LocalBluetoothPairingError);
        break;
    case QBluetoothLocalDevice::UnknownError:
        emit signalBluetoothState(BluetoothState_LocalBluetoothUnknownError);
        break;
    default:
        emit signalBluetoothState(BluetoothState_LocalBluetoothUnknownError);
        break;
    }
}

QVariantMap BluetoothCtrl::getLocalDeviceInfo()
{
    bool isValid = mLocalBluetooth.isValid();
    QString deviceName = mLocalBluetooth.name();
    QString deviceAddr = mLocalBluetooth.address().toString();
    QBluetoothLocalDevice::HostMode hostMode = mLocalBluetooth.hostMode();
    QString strHostMode;
    switch (hostMode) {
    case QBluetoothLocalDevice::HostPoweredOff:
    {
        strHostMode = tr("关闭");
    } break;
    case QBluetoothLocalDevice::HostConnectable:
    {
        strHostMode = tr("可连接");
    } break;
    case QBluetoothLocalDevice::HostDiscoverable:
    {
        strHostMode = tr("可见");
    } break;
    case QBluetoothLocalDevice::HostDiscoverableLimitedInquiry:
    {
        strHostMode = tr("有限可见");
    } break;

    }
    QList<QBluetoothAddress> connectedDevicesList = mLocalBluetooth.connectedDevices();
    QList<QBluetoothHostInfo> infoList = QBluetoothLocalDevice::allDevices();

#if 0
    qDebug() << "************************************************";
    mLocalBluetooth.powerOn();
    qDebug() << "mLocalBluetooth isValid:" << mLocalBluetooth.isValid();
    qDebug() << "mLocalBluetooth.name: " << mLocalBluetooth.name();
    QBluetoothAddress localAddr = mLocalBluetooth.address();
    qDebug() << "localAddr: " << localAddr;
    QList<QBluetoothAddress> connectedDevicesList = mLocalBluetooth.connectedDevices();
    qDebug() << "connectedDevicesList: " << connectedDevicesList;
    mLocalBluetooth.powerOn();
    qDebug() << "hostMode: " << mLocalBluetooth.hostMode();
    QList<QBluetoothHostInfo> infoList = QBluetoothLocalDevice::allDevices();
    qDebug() << "QBluetoothLocalDevice::allDevices(): " << infoList.size();
    for (int i = 0; i < infoList.size(); ++i)
    {
        qDebug() << infoList[i].name() << " ---- " << infoList[i].address();
    }
    qDebug() << "************************************************";
#endif

    return {{"isValid", isValid}, {"deviceName", deviceName}, {"deviceAddr", deviceAddr}, {"hostMode", strHostMode}, {"connectedDevicesCount", connectedDevicesList.count()}};
}

QString BluetoothCtrl::byteArrayToString(const QByteArray& byteArray)
{
#if 0
    {
        QString strResult;
        for (int i = 0; i < byteArray.count(); ++i)
        {
            char byteData = byteArray.at(i);
            if(QChar::isPrint(static_cast<uint>(byteData)))
            {
                strResult.append(QChar::fromLatin1(byteData));
            }
            else
            {
                strResult.append("\\x");
                strResult.append(byteArray.mid(i, 1).toHex());
            }
        }
        return strResult;
    }
#endif

    QString str;
    QDebug debug(&str);
    debug = debug.nospace();
    //debug = debug.noquote();
    debug.setAutoInsertSpaces(false);
    debug.setVerbosity(QDebug::MinimumVerbosity);
    debug << byteArray;
    if(!str.isEmpty() && str.at(0) == '\"')
    {
        str = str.right(str.length() -1);
    }
    if(!str.isEmpty() && str.back() == '\"')
    {
        str = str.left(str.length() -1);
    }
    while(true)
    {
        int findIndex = str.indexOf(QRegularExpression("\\\\x[0-9A-F][0-9A-F]\""));
        if(findIndex == -1)
        {
            break;
        }
        str.remove(findIndex + 4, 1);
        if(str.length() > findIndex + 4 && str.at(findIndex + 4) == "\"")
        {
            str.remove(findIndex + 4, 1);
        }
    }

    return str;
}

bool BluetoothCtrl::StringToByteArray(const QString &strData, EnumCharset charset, QByteArray &byteData)
{
    switch (charset)
    {
    case BluetoothCtrl::EnumCharset_HEX:
        byteData = QByteArray::fromHex(strData.toUtf8());
        break;
    case BluetoothCtrl::EnumCharset_GBK:
        if(QTextCodec *codec = QTextCodec::codecForName("GB18030"))
        {// 转成GBK
            byteData = codec->fromUnicode(strData);
        }
        else
        {
            qDebug() << "GB18030 codec create failed";
            return false;
        }
        break;
    case BluetoothCtrl::EnumCharset_UTF8:
        byteData = strData.toUtf8();
        break;
    case BluetoothCtrl::EnumCharset_UNICODE:
        byteData.append(reinterpret_cast<const char *>(strData.unicode()), strData.length()*2);
        //byteData.append(reinterpret_cast<const char *>(strData.data()), strData.length()*2);
        //byteData.append(reinterpret_cast<const char *>(strData.data()), strData.length()*2);
        break;
    }
    return true;
}


// /////////////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////////////
void BluetoothCtrl::deviceDiscoveryAgentDeviceDiscovered(const QBluetoothDeviceInfo &info)
{
    emit signalBluetoothState(BluetoothCtrl::BluetoothState_DeviceNewDiscovered);

    bool bStopDiscovery = false;
    if(!mstrDeviceFilter.isEmpty())
    {
        if(-1 == info.name().indexOf(mstrDeviceFilter, 0, Qt::CaseInsensitive)
                || -1 == info.address().toString().indexOf(mstrDeviceFilter, 0, Qt::CaseInsensitive))
        {// 过滤掉
            return ;
        }
        if(mstrDeviceFilter == info.name() || mstrDeviceFilter == info.address().toString())
        {
            bStopDiscovery = true;
        }
    }

    if(this->mDeviceModel)
    {// 添加到列表模型
        this->mDeviceModel->addDevice(info.name()
                                      , info.address().toString()
                                      , info.rssi()
                                      , info.coreConfigurations().testFlag(QBluetoothDeviceInfo::LowEnergyCoreConfiguration)
                                      , QBluetoothLocalDevice::Unpaired != mLocalBluetooth.pairingStatus(info.address())
                , info
                                      );
    }
    // 在搜索设备时查找服务会找不都服务，只加入列表等待，要等到搜索设备结束
    mDiscoveredDeviceList.append(info);
    if(bStopDiscovery)
    {
        mDeviceDiscoveryAgent.stop();
    }

#if 1
    {
        qDebug() << "################";
        qDebug() << "Found new device:" << info.name() << " " << info.address().toString() << " " << info.deviceUuid()
                 << ", serviceClasses():" << info.serviceClasses()
                 << ",majorDeviceClass():" << info.majorDeviceClass()
                 << ",coreConfigurations():" << info.coreConfigurations()
                 << (info.coreConfigurations().testFlag(QBluetoothDeviceInfo::LowEnergyCoreConfiguration) ? ",it is LowEnergyCoreConfiguration" : "")
                 << ",status:" << mLocalBluetooth.pairingStatus(info.address())
                 << ",manufacturerIds:" << info.manufacturerIds()
                 << (info.manufacturerIds().empty()?"":info.manufacturerData(info.manufacturerIds().at(0)))
                    ;
        QList<QBluetoothUuid> uuidList = info.serviceUuids();
        qDebug() << "serviceUuids: " << uuidList.size() << " " << uuidList;
        qDebug() << "################";
    }
#endif
}

void BluetoothCtrl::deviceDiscoveryAgentDeviceUpdated(const QBluetoothDeviceInfo &info, QBluetoothDeviceInfo::Fields updatedFields)
{
    Q_UNUSED(info);
    Q_UNUSED(updatedFields);
    //qDebug() << "DeviceDiscoveryAgentDeviceUpdated:" << info.name() << " " << info.address() << info.rssi() << updatedFields;
    if(updatedFields.testFlag(QBluetoothDeviceInfo::Field::RSSI))
    {
        if(this->mDeviceModel)
        {
            this->mDeviceModel->updateRssi(info.address().toString(), info.rssi());
        }
    }
    else if(updatedFields.testFlag(QBluetoothDeviceInfo::Field::ManufacturerData))
    {
        qDebug() << "DeviceDiscoveryAgentDeviceUpdated:" << info.name() << " " << info.address() << info.rssi() << updatedFields;
        qDebug() << "manufacturerData: " << info.manufacturerData();
    }
    else if(updatedFields.testFlag(QBluetoothDeviceInfo::Field::All))
    {
        qDebug() << "DeviceDiscoveryAgentDeviceUpdated:" << info.name() << " " << info.address() << info.rssi() << updatedFields;
        if(this->mDeviceModel)
        {
            this->mDeviceModel->updateDeviceName(info.name(), info.address().toString());
        }
    }
}

void BluetoothCtrl::deviceDiscoveryAgentDiscoveredFinished()
{
    emit signalBluetoothState(BluetoothCtrl::BluetoothState_DeviceEnd);
    qDebug() << "DeviceDiscoveryAgentDiscoveredFinished";
    // 必须是设备查找结束后才能开始服务搜索
    startServiceScanFromDiscoveredDeviceList();
}

void BluetoothCtrl::deviceDiscoveryAgentError(QBluetoothDeviceDiscoveryAgent::Error error)
{
    //emit signalBluetoothState(BluetoothState_DeviceError);
    qDebug() << "DeviceDiscoveryAgentError:" << error;
    switch (error) {
    case QBluetoothDeviceDiscoveryAgent::NoError:
        break;
    case QBluetoothDeviceDiscoveryAgent::InputOutputError:
        emit signalBluetoothState(BluetoothState_InputOutputError);
        break;
    case QBluetoothDeviceDiscoveryAgent::PoweredOffError:
        emit signalBluetoothState(BluetoothState_PoweredOffError);
        break;
    case QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError:
        emit signalBluetoothState(BluetoothState_InvalidBluetoothAdapterError);
        break;
    case QBluetoothDeviceDiscoveryAgent::UnsupportedPlatformError:
        emit signalBluetoothState(BluetoothState_UnsupportedPlatformError);
        break;
    case QBluetoothDeviceDiscoveryAgent::UnsupportedDiscoveryMethod:
        emit signalBluetoothState(BluetoothState_UnsupportedDiscoveryMethod);
        break;
    case QBluetoothDeviceDiscoveryAgent::UnknownError: //= 100 // New errors must be added before Unknown error
        emit signalBluetoothState(BluetoothState_DeviceDiscoveryAgentUnknownError);
        break;
    default:
        emit signalBluetoothState(BluetoothState_DeviceDiscoveryAgentUnknownError);
        break;
    }
}

void BluetoothCtrl::deviceDiscoveryAgentCanceled()
{
    emit signalBluetoothState(BluetoothCtrl::BluetoothState_DeviceCancel);
    qDebug() << "DeviceDiscoveryAgentCanceled:";
    startServiceScanFromDiscoveredDeviceList();
}

bool BluetoothCtrl::startDeviceScan()
{
    //qDebug() << "isActive:" << mDeviceDiscoveryAgent.isActive();
    if(!mDeviceDiscoveryAgent.isActive())
    {
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_DeviceStart);
        mDeviceDiscoveryAgent.start();
        //mDeviceDiscoveryAgent.start(QBluetoothDeviceDiscoveryAgent::ClassicMethod);
        //mDeviceDiscoveryAgent.start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
        qDebug() << "StartDeviceSearch";
        return true;
    }
    return false;
}

bool BluetoothCtrl::stopDeviceScan()
{
    while(mDeviceDiscoveryAgent.isActive())
    {
        mDeviceDiscoveryAgent.stop();
        QThread::yieldCurrentThread();
    }
    return true;
}

void BluetoothCtrl::setDeviceFilter(const QString& filter)
{
    mstrDeviceFilter = filter;
}

QString BluetoothCtrl::getDeviceFilter()
{
    return mstrDeviceFilter;
}
// /////////////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////////////
void BluetoothCtrl::serviceDiscovered(const QBluetoothServiceInfo &info)
{
    emit signalBluetoothState(BluetoothCtrl::BluetoothState_ServiceNewDiscovered);
    qDebug() << "ServiceDiscovered:##########################";
    if(this->mDeviceModel)
    {
        // 添加到列表模型
        QList<QBluetoothUuid> serviceClassUuids = info.serviceClassUuids();
        for(int i = 0; i < serviceClassUuids.size(); ++i)
        {
            this->mDeviceModel->addService(info.serviceName()
                                           , info.socketProtocol()
                                           , serviceClassUuids.at(i).toString()
                                           , info
                                           , info.device().name()
                                           , info.device().address().toString()
                                           , info.device()
                                           );
        }
    }
    qDebug() << "ServiceDiscovered:"
             << ",serviceName:" << info.serviceName()
                //<< ",serviceDescription:" << info.serviceDescription()
                //<< ",serviceProvider:" << info.serviceProvider()
             << ",serviceProvider:" << info.socketProtocol()
                //<< ",serviceUuid:" << info.serviceUuid()
             << ",serviceClassUuids:" << info.serviceClassUuids()
             << ",deviceName:" << info.device().name()
             << ",deviceAddr:" << info.device().address()
                ;
}

void BluetoothCtrl::serviceDiscoveryFinished()
{
    emit signalBluetoothState(BluetoothCtrl::BluetoothState_ServiceEnd);
    QList<QBluetoothServiceInfo> discoveredServicesList = mServiceDiscoveryAgent.discoveredServices();
    qDebug() << "ServiceDiscoveryFinished" << "discoveredServices:size()" << discoveredServicesList.size();

    // 继续扫描
    startServiceScanFromDiscoveredDeviceList();
}

void BluetoothCtrl::serviceError(QBluetoothServiceDiscoveryAgent::Error error)
{
    //emit signalBluetoothState(BluetoothCtrl::BluetoothState_ServiceError);
    // 继续扫描
    startServiceScanFromDiscoveredDeviceList();
    qDebug() << "ServiceError:" << error;
    switch (error) {
    case QBluetoothServiceDiscoveryAgent::NoError:// =  QBluetoothDeviceDiscoveryAgent::NoError,
        break;
    case QBluetoothServiceDiscoveryAgent::InputOutputError:// = QBluetoothDeviceDiscoveryAgent::InputOutputError,
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_InputOutputError);
        break;
    case QBluetoothServiceDiscoveryAgent::PoweredOffError:// = QBluetoothDeviceDiscoveryAgent::PoweredOffError,
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_PoweredOffError);
        break;
    case QBluetoothServiceDiscoveryAgent::InvalidBluetoothAdapterError:// = QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError,
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_InvalidBluetoothAdapterError);
        break;
    case QBluetoothServiceDiscoveryAgent::UnknownError:// = QBluetoothDeviceDiscoveryAgent::UnknownError //=100
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_BluetoothServiceUnknownError);
        break;
        //New Errors must be added after Unknown Error the space before UnknownError is reserved
        //for future device discovery errors
    default:
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_BluetoothServiceUnknownError);
        break;
    }
}

void BluetoothCtrl::serviceDiscoveryCanceled()
{
    emit signalBluetoothState(BluetoothCtrl::BluetoothState_ServiceCancel);
    qDebug() << "serviceDiscoveryCanceled";
}

bool BluetoothCtrl::startServiceScan()
{
    if(!mServiceDiscoveryAgent.isActive())
    {
        //        if(this->mDeviceModel)
        //        {
        //            this->mDeviceModel->clear();
        //        }
        mServiceDiscoveryAgent.clear();
        //mServiceDiscoveryAgent.setRemoteAddress(info.address());
        //mServiceDiscoveryAgent.setRemoteAddress(QBluetoothAddress("00:15:87:21:0F:1D"));
        //mServiceDiscoveryAgent.setRemoteAddress(QBluetoothAddress("20:18:08:30:41:20"));
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_ServiceStart);
        mServiceDiscoveryAgent.start(QBluetoothServiceDiscoveryAgent::FullDiscovery);
        qDebug() << "startServiceSearch";
        return true;
    }
    return false;
}

bool BluetoothCtrl::startServiceScan(const QBluetoothAddress &address)
{
    if(!mServiceDiscoveryAgent.isActive())
    {
        //        if(this->mDeviceModel)
        //        {
        //            this->mDeviceModel->clear();
        //        }
        mServiceDiscoveryAgent.clear();
        mServiceDiscoveryAgent.setRemoteAddress(address);
        //mServiceDiscoveryAgent.setRemoteAddress(QBluetoothAddress(address.toString()));
        //mServiceDiscoveryAgent.setRemoteAddress(QBluetoothAddress("00:15:87:21:0F:1D"));
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_ServiceStart);
        mServiceDiscoveryAgent.start(QBluetoothServiceDiscoveryAgent::FullDiscovery);
        qDebug() << "StartServiceSearch:" << address;
        return true;
    }
    return false;
}

bool BluetoothCtrl::startServiceScanFromDiscoveredDeviceList()
{
    if(!mDiscoveredDeviceList.empty())
    {// 继续扫描
        QBluetoothDeviceInfo deviceInfo = mDiscoveredDeviceList.at(0);
        if(startServiceScan(deviceInfo.address()))
        {
            mDiscoveredDeviceList.removeFirst();
            return true;
        }
        else
        {
            qDebug() << "StartServiceScan failed";
            return false;
        }
    }
    else
    {
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_ServiceEndAllDevice);
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_NoScan);
        qDebug() << "mDiscoveredDeviceList is empty";
        return false;
    }
}

bool BluetoothCtrl::stopServiceScan()
{
    mDiscoveredDeviceList.clear();
    while(mServiceDiscoveryAgent.isActive())
    {
        mServiceDiscoveryAgent.stop();
        QThread::yieldCurrentThread();
    }
    return true;
}
// /////////////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////////////
void BluetoothCtrl::bluetoothSocketConnected()
{
    emit signalBluetoothState(BluetoothCtrl::BluetoothState_SocketConnected);
    qDebug() << "bluetoothSocketConnected"
             << ",peerName:"<< mpBluetoothSocket->peerName()
             << ",peerAddress:" << mpBluetoothSocket->peerAddress()
             << ",peerPort:" << mpBluetoothSocket->peerPort()
             << ",socketDescriptor:" << mpBluetoothSocket->socketDescriptor()
             << ",socketType:" << mpBluetoothSocket->socketType()
             << ",state:" << mpBluetoothSocket->state()
             << ",preferredSecurityFlags:" << mpBluetoothSocket->preferredSecurityFlags()
                ;
    if(!mpBluetoothSocket->peerName().isEmpty() && this->mDeviceModel)
    {
        this->mDeviceModel->updateDeviceName(mpBluetoothSocket->peerName(), mpBluetoothSocket->peerAddress().toString());
    }
    if(this->mDeviceModel)
    {
        this->mDeviceModel->updateSocketConnectState(this->mSocketPeerAddress, this->mSocketPeerServiceUUID, true);
    }
}

void BluetoothCtrl::bluetoothSocketDisconnected()
{
    emit signalBluetoothState(BluetoothCtrl::BluetoothState_SocketDisconnected);
    qDebug() << "bluetoothSocketDisconnected";
    if(this->mpBluetoothSocket)
    {// 这里不能删除对象，会崩溃
        //this->mpBluetoothSocket.reset();
    }
    if(this->mDeviceModel)
    {
        this->mDeviceModel->updateSocketConnectState(this->mSocketPeerAddress, this->mSocketPeerServiceUUID, false);
    }
    //
    this->mSocketPeerAddress = "";
    this->mSocketPeerServiceUUID = "";
    this->mSocketPeerProtocol = 0;
}

void BluetoothCtrl::bluetoothSocketError(QBluetoothSocket::SocketError error)
{
    //emit signalBluetoothState(BluetoothCtrl::BluetoothState_SocketError);
    qDebug() << "bluetoothSocketError:" << error;
    switch (error) {
    case QBluetoothSocket::NoSocketError:// = -2,
        break;
    case QBluetoothSocket::UnknownSocketError:// = QAbstractSocket::UnknownSocketError, //-1
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_UnknownSocketError);
        break;
    case QBluetoothSocket::RemoteHostClosedError:// = QAbstractSocket::RemoteHostClosedError, //1
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_RemoteHostClosedError);
        break;
    case QBluetoothSocket::HostNotFoundError:// = QAbstractSocket::HostNotFoundError, //2
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_HostNotFoundError);
        break;
    case QBluetoothSocket::ServiceNotFoundError:// = QAbstractSocket::SocketAddressNotAvailableError, //9
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_ServiceNotFoundError);
        break;
    case QBluetoothSocket::NetworkError:// = QAbstractSocket::NetworkError, //7
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_NetworkError);
        break;
    case QBluetoothSocket::UnsupportedProtocolError:// = 8,
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_UnsupportedProtocolError);
        break;
    case QBluetoothSocket::OperationError:// = QAbstractSocket::OperationError //19
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_OperationError);
        break;
        //New enums (independent of QAbstractSocket) should be added from 100 onwards
    default:
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_UnknownSocketError);
        break;
    }
}

void BluetoothCtrl::bluetoothSocketStateChanged(QBluetoothSocket::SocketState state)
{
    qDebug() << "bluetoothSocketStateChanged:" << state;
    if(QBluetoothSocket::UnconnectedState == state)
    {
    }
}

void BluetoothCtrl::bluetoothSocketReadyRead()
{
    QByteArray dataArray = mpBluetoothSocket->readAll();
    ProcessReceiveData(dataArray);
    qDebug() << "bluetoothSocketReadyRead:" << dataArray;
}

void BluetoothCtrl::bluetoothSocketBytesWritten(qint64 bytes)
{
    qDebug() << "bluetoothSocketBytesWritten:" << bytes;
    emit signalSendByteLength(static_cast<int>(bytes));
}

bool BluetoothCtrl::connectSocket(const QBluetoothServiceInfo &service)
{
    qDebug() << "ConnectSocket:" << service.device().address() << "  " << service.serviceClassUuids();
    // 停止清理搜索
    stopDeviceScan();
    stopServiceScan();
    disconnectLowEnergyDevice();
    // 创建socket
    disconnectSocket();
    mpBluetoothSocket.reset(new QBluetoothSocket());
    //mpBluetoothSocket =  new QBluetoothSocket(QBluetoothServiceInfo::UnknownProtocol);
    //mpBluetoothSocket =  new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
    //mpBluetoothSocket =  new QBluetoothSocket(QBluetoothServiceInfo::L2capProtocol);
    //mpBluetoothSocket =  new QBluetoothSocket(discoveredServicesList[i].socketProtocol());

    // 连接槽
    connect(mpBluetoothSocket.get(), SIGNAL(connected()), this, SLOT(bluetoothSocketConnected()));
    connect(mpBluetoothSocket.get(), SIGNAL(disconnected()), this, SLOT(bluetoothSocketDisconnected()));
    connect(mpBluetoothSocket.get(), SIGNAL(error(QBluetoothSocket::SocketError)), this, SLOT(bluetoothSocketError(QBluetoothSocket::SocketError)));
    connect(mpBluetoothSocket.get(), SIGNAL(stateChanged(QBluetoothSocket::SocketState)), this, SLOT(bluetoothSocketStateChanged(QBluetoothSocket::SocketState)));
    connect(mpBluetoothSocket.get(), SIGNAL(readyRead()), this, SLOT(bluetoothSocketReadyRead()));
    connect(mpBluetoothSocket.get(), SIGNAL(bytesWritten(qint64)), this, SLOT(bluetoothSocketBytesWritten(qint64)));
    //
    this->mSocketPeerAddress = service.device().address().toString();
    this->mSocketPeerServiceUUID = service.serviceUuid().toString();
    this->mSocketPeerProtocol = service.socketProtocol();
    // 连接蓝牙服务
    emit signalBluetoothState(BluetoothCtrl::BluetoothState_SocketConnectStart);
    mpBluetoothSocket->connectToService(service, QIODevice::ReadWrite);
    //mpBluetoothSocket->connectToService(info.device().address(), 1, QIODevice::ReadWrite);
    //mpBluetoothSocket->connectToService(info.device().address(), info.serviceClassUuids().at(0), QIODevice::ReadWrite);

    return true;
}

bool BluetoothCtrl::connectSocket(const QString &address, const QString &uuid, int socketProtocol)
{
    qDebug() << "ConnectSocket:" << address << "  " << uuid;
    // 停止清理搜索
    stopDeviceScan();
    stopServiceScan();
    disconnectLowEnergyDevice();
    // 创建socket
    disconnectSocket();
    mpBluetoothSocket.reset(new QBluetoothSocket(QBluetoothServiceInfo::Protocol(socketProtocol)));
    //mpBluetoothSocket =  new QBluetoothSocket(QBluetoothServiceInfo::UnknownProtocol);
    //mpBluetoothSocket =  new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
    //mpBluetoothSocket =  new QBluetoothSocket(QBluetoothServiceInfo::L2capProtocol);
    //mpBluetoothSocket =  new QBluetoothSocket(discoveredServicesList[i].socketProtocol());

    // 连接槽
    connect(mpBluetoothSocket.get(), SIGNAL(connected()), this, SLOT(bluetoothSocketConnected()));
    connect(mpBluetoothSocket.get(), SIGNAL(disconnected()), this, SLOT(bluetoothSocketDisconnected()));
    connect(mpBluetoothSocket.get(), SIGNAL(error(QBluetoothSocket::SocketError)), this, SLOT(bluetoothSocketError(QBluetoothSocket::SocketError)));
    connect(mpBluetoothSocket.get(), SIGNAL(stateChanged(QBluetoothSocket::SocketState)), this, SLOT(bluetoothSocketStateChanged(QBluetoothSocket::SocketState)));
    connect(mpBluetoothSocket.get(), SIGNAL(readyRead()), this, SLOT(bluetoothSocketReadyRead()));
    connect(mpBluetoothSocket.get(), SIGNAL(bytesWritten(qint64)), this, SLOT(bluetoothSocketBytesWritten(qint64)));
    //
    this->mSocketPeerAddress = address;
    this->mSocketPeerServiceUUID = uuid;
    this->mSocketPeerProtocol = socketProtocol;
    // 连接蓝牙服务
    emit signalBluetoothState(BluetoothCtrl::BluetoothState_SocketConnectStart);
    //mpBluetoothSocket->connectToService(service, QIODevice::ReadWrite);
    //mpBluetoothSocket->connectToService(info.device().address(), 1, QIODevice::ReadWrite);
    mpBluetoothSocket->connectToService(QBluetoothAddress(address), QBluetoothUuid(uuid), QIODevice::ReadWrite);

    return true;
}

bool BluetoothCtrl::disconnectSocket()
{
    if(mpBluetoothSocket && mpBluetoothSocket->state() == QBluetoothSocket::ConnectedState)
    {
        mpBluetoothSocket->disconnectFromService();
        //mpBluetoothSocket.reset();// 这里删除对象会造成断开socket消息收不到
    }
    return true;
}

// /////////////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////////////
void BluetoothCtrl::lowEnergyCtrlConnected()
{
    emit signalBluetoothState(BluetoothCtrl::BluetoothState_LowEnergyConnected);
    qDebug() << "lowEnergyCtrlConnected:" << mpLowEnergyCtrl->remoteName() << "  " << mpLowEnergyCtrl->remoteAddress();
    if (mpLowEnergyCtrl)
    {
        qDebug() << "lowEnergyCtrlConnected::start discoverServices";
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_LowEnergyDiscoverServiceStart);
        mpLowEnergyCtrl->discoverServices();
    }
}

void BluetoothCtrl::lowEnergyCtrlDisconnected()
{
    emit signalBluetoothState(BluetoothCtrl::BluetoothState_LowEnergyDisconnected);
    qDebug() << "lowEnergyCtrlDisconnected:";
    mpLowEnergyCtrl.reset();
}

void BluetoothCtrl::lowEnergyCtrlStateChanged(QLowEnergyController::ControllerState state)
{
    qDebug() << "lowEnergyCtrlStateChanged:" << state;
}

void BluetoothCtrl::lowEnergyCtrlError(QLowEnergyController::Error newError)
{
    //emit signalBluetoothState(BluetoothCtrl::BluetoothState_LowEnergyError);
    qDebug() << "lowEnergyCtrlError:" << newError;
    switch (newError) {
    case QLowEnergyController::NoError:
        break;
    case QLowEnergyController::UnknownError:
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_LowEnergyCtrlUnknownError);
        break;
    case QLowEnergyController::UnknownRemoteDeviceError:
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_LowEnergyCtrlUnknownRemoteDeviceError);
        break;
    case QLowEnergyController::NetworkError:
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_LowEnergyCtrlNetworkError);
        break;
    case QLowEnergyController::InvalidBluetoothAdapterError:
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_LowEnergyCtrlInvalidBluetoothAdapterError);
        break;
    case QLowEnergyController::ConnectionError:
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_LowEnergyCtrlConnectionError);
        break;
    case QLowEnergyController::AdvertisingError:
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_LowEnergyCtrlAdvertisingError);
        break;
    case QLowEnergyController::RemoteHostClosedError:
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_LowEnergyCtrlRemoteHostClosedError);
        break;
    default:
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_LowEnergyCtrlUnknownError);
        break;

    }
}

void BluetoothCtrl::lowEnergyCtrlServiceDiscovered(const QBluetoothUuid &newService)
{
    emit signalBluetoothState(BluetoothCtrl::BluetoothState_LowEnergyDiscoverNewService);
    qDebug() << "lowEnergyCtrlServiceDiscovered:" << newService << "  " << mpLowEnergyCtrl->remoteName() << "  " << mpLowEnergyCtrl->remoteAddress();

    if(1)
    {
        QSharedPointer<QLowEnergyService> pLowEnergyService(mpLowEnergyCtrl->createServiceObject(newService, this));
        if(pLowEnergyService)
        {
            connect(pLowEnergyService.get(), &QLowEnergyService::stateChanged, this, &BluetoothCtrl::lowEnergyServiceStateChanged);
            connect(pLowEnergyService.get(), &QLowEnergyService::characteristicChanged, this, &BluetoothCtrl::lowEnergyServiceCharacteristicChanged);
            connect(pLowEnergyService.get(), &QLowEnergyService::characteristicRead, this, &BluetoothCtrl::lowEnergyServiceCharacteristicRead);
            connect(pLowEnergyService.get(), &QLowEnergyService::characteristicWritten, this, &BluetoothCtrl::lowEnergyServiceCharacteristicWritten);
            connect(pLowEnergyService.get(), &QLowEnergyService::descriptorRead, this, &BluetoothCtrl::lowEnergyServiceDescriptorRead);
            connect(pLowEnergyService.get(), &QLowEnergyService::descriptorWritten, this, &BluetoothCtrl::lowEnergyServiceDescriptorWritten);
            connect(pLowEnergyService.get(), SIGNAL(error(QLowEnergyService::ServiceError)), this, SLOT(lowEnergyServiceError(QLowEnergyService::ServiceError)));
            if (pLowEnergyService)
            {
                qDebug() << "lowEnergyServiceName:" << pLowEnergyService->serviceName()
                         << ",LowEnergyType:" << pLowEnergyService->type()
                         << ",LowEnergyState:" << pLowEnergyService->state();
            }
            if(this->mLowEnergyModel)
            {// 添加到列表
                this->mLowEnergyModel->addService(pLowEnergyService->serviceName(), pLowEnergyService->serviceUuid().toString());
            }
            mLowEnergyServiceList.append(pLowEnergyService);
            pLowEnergyService->discoverDetails();
        }
    }
}

void BluetoothCtrl::lowEnergyCtrlDiscoveryFinished()
{
    qDebug() << "lowEnergyCtrlDiscoveryFinished:";

    lowEnergyServiceDiscoverDetails();

    return ;

#if 0
    if (mpLowEnergyCtrl)
    {
        QList<QBluetoothUuid> uuidList = mpLowEnergyCtrl->services();
        qDebug() << "QLowEnergyController::services: " << uuidList.size();
        for (int i = 0; i < uuidList.size(); ++i)
        {
            qDebug() << uuidList[i];

            if (uuidList[i] == QBluetoothUuid(QLatin1String("{0000ffe0-0000-1000-8000-00805f9b34fb}"))
                    //                    || uuidList[i] == QBluetoothUuid(QLatin1String("{0000fff0-0000-1000-8000-00805f9b34fb}"))
                    )
            {
                //qDebug() << "************************************************";
                mLowEnergyCharacteristicSelected = QLowEnergyCharacteristic();  // 置无效

                mpLowEnergyService.reset(mpLowEnergyCtrl->createServiceObject(uuidList[i], this));
                if(!mpLowEnergyService)
                {
                    qDebug() << "createServiceObject failed";
                    return ;
                }
                connect(mpLowEnergyService.get(), &QLowEnergyService::stateChanged, this, &BluetoothCtrl::lowEnergyServiceStateChanged);
                connect(mpLowEnergyService.get(), &QLowEnergyService::characteristicChanged, this, &BluetoothCtrl::lowEnergyServiceCharacteristicChanged);
                connect(mpLowEnergyService.get(), &QLowEnergyService::characteristicRead, this, &BluetoothCtrl::lowEnergyServiceCharacteristicRead);
                connect(mpLowEnergyService.get(), &QLowEnergyService::characteristicWritten, this, &BluetoothCtrl::lowEnergyServiceCharacteristicWritten);
                connect(mpLowEnergyService.get(), &QLowEnergyService::descriptorRead, this, &BluetoothCtrl::lowEnergyServiceDescriptorRead);
                connect(mpLowEnergyService.get(), &QLowEnergyService::descriptorWritten, this, &BluetoothCtrl::lowEnergyServiceDescriptorWritten);
                connect(mpLowEnergyService.get(), SIGNAL(error(QLowEnergyService::ServiceError)), this, SLOT(lowEnergyServiceError(QLowEnergyService::ServiceError)));
                if (mpLowEnergyService)
                {
                    qDebug() << "lowEnergyServiceName:" << mpLowEnergyService->serviceName()
                             << ",LowEnergyType:" << mpLowEnergyService->type()
                             << ",LowEnergyState:" << mpLowEnergyService->state();
                }
                mpLowEnergyService->discoverDetails();
                break;
            }

            qDebug() << "************************************************";
        }
    }
#endif
}

bool BluetoothCtrl::lowEnergyServiceDiscoverDetails()
{
#if 0
    if(!mLowEnergyServiceList.isEmpty() && miDiscoverDetailsIndex < mLowEnergyServiceList.length() - 1)
    {
        ++miDiscoverDetailsIndex;
        mLowEnergyServiceList.at(miDiscoverDetailsIndex)->discoverDetails();
        return true;
    }
    else
    {
        qDebug() << "discoverDetails all finish";
        return false;
    }
#else
    return false;
#endif
}

void BluetoothCtrl::lowEnergyCtrlConnectionUpdated(const QLowEnergyConnectionParameters &parameters)
{
    Q_UNUSED(parameters)
    qDebug() << "lowEnergyCtrlConnectionUpdated:";
}

void BluetoothCtrl::lowEnergyServiceStateChanged(QLowEnergyService::ServiceState newState)
{
    qDebug() << "lowEnergyServiceStateChanged:" << newState;
    if(QLowEnergyService::DiscoveringServices == newState)
    {
        //qDebug() << tr("Discovering services...");
    }
    else if (QLowEnergyService::ServiceDiscovered == newState)
    {
        lowEnergyServiceDiscoverDetails();
        if(QLowEnergyService* pLowEnergyService = qobject_cast<QLowEnergyService*>(sender()))
        {
            QList<QLowEnergyCharacteristic> pLowEnergyCharacteristicList = pLowEnergyService->characteristics();
            for(int i = 0; i < pLowEnergyCharacteristicList.size(); ++i)
            {
                QLowEnergyCharacteristic& lowEnergyCharacteristic = pLowEnergyCharacteristicList[i];
                if(this->mLowEnergyModel)
                {// 添加到列表
                    this->mLowEnergyModel->addCharacteristic(lowEnergyCharacteristic.name(), lowEnergyCharacteristic.uuid().toString()
                                                             , int(lowEnergyCharacteristic.properties()), byteArrayToString(lowEnergyCharacteristic.value())
                                                             , pLowEnergyService->serviceName(), pLowEnergyService->serviceUuid().toString());
                }
                qDebug() << "QLowEnergyCharacteristic::name: " << lowEnergyCharacteristic.name()
                         << ", QLowEnergyCharacteristic::uuid: " << lowEnergyCharacteristic.uuid()
                         << ", QLowEnergyCharacteristic::value: " << lowEnergyCharacteristic.value() << "  " << byteArrayToString(lowEnergyCharacteristic.value())
                         << ", QLowEnergyCharacteristic::properties: " << lowEnergyCharacteristic.properties()
                         << ", QLowEnergyCharacteristic::descriptors.size(): " << lowEnergyCharacteristic.descriptors().size()
                            ;

                QList<QLowEnergyDescriptor> lowEnergyDescriptorList = lowEnergyCharacteristic.descriptors();
                //qDebug() << "descriptors: " << lowEnergyDescriptorList.size();
                for (int i = 0; i < lowEnergyDescriptorList.size(); ++i)
                {
                    QLowEnergyDescriptor& lowEnergyDescriptor = lowEnergyDescriptorList[i];
                    if(this->mLowEnergyModel)
                    {// 添加到列表
                        this->mLowEnergyModel->addDescriptor(lowEnergyDescriptor.name(), lowEnergyDescriptor.uuid().toString(), byteArrayToString(lowEnergyDescriptor.value())
                                                             , lowEnergyCharacteristic.name(), lowEnergyCharacteristic.uuid().toString()
                                                             , pLowEnergyService->serviceName(), pLowEnergyService->serviceUuid().toString()
                                                             );
                    }
                    qDebug() << "QLowEnergyDescriptor:" << lowEnergyDescriptor.name()
                             << "  " << lowEnergyDescriptor.uuid()
                             << "  " << QBluetoothUuid::descriptorToString(lowEnergyDescriptor.type())
                             << "  " << lowEnergyDescriptor.value() << "  " <<  byteArrayToString(lowEnergyDescriptor.value())
                                ;
                }
            }
        }
#if 0
        if(0 && mpLowEnergyService)
        {
            QList<QLowEnergyCharacteristic> pLowEnergyCharacteristicList = mpLowEnergyService->characteristics();
            qDebug() << "*************************\r\npLowEnergyCharacteristicList size():" << pLowEnergyCharacteristicList.size();
            if (pLowEnergyCharacteristicList.size() > 0)
            {
                QLowEnergyCharacteristic lowEnergyCharacteristic = pLowEnergyCharacteristicList[0];
                qDebug() << "QLowEnergyCharacteristic::name: " << lowEnergyCharacteristic.name();
                qDebug() << "QLowEnergyCharacteristic::uuid: " << lowEnergyCharacteristic.uuid();
                qDebug() << "QLowEnergyCharacteristic::value: " << lowEnergyCharacteristic.value();
                qDebug() << "QLowEnergyCharacteristic::properties: " << lowEnergyCharacteristic.properties();
                qDebug() << "QLowEnergyCharacteristic::descriptors.size(): " << lowEnergyCharacteristic.descriptors().size();

                QList<QLowEnergyDescriptor> lowEnergyDescriptorList = lowEnergyCharacteristic.descriptors();
                //qDebug() << "descriptors: " << lowEnergyDescriptorList.size();
                for (int i = 0; i < lowEnergyDescriptorList.size(); ++i)
                {
                    qDebug() << lowEnergyDescriptorList[i].name()
                             << "  " << lowEnergyDescriptorList[i].uuid()
                             << "  " << lowEnergyDescriptorList[i].type()
                             << "  " << lowEnergyDescriptorList[i].value()
                                ;
                }
                QLowEnergyDescriptor notificationDesc = lowEnergyCharacteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
                if (notificationDesc.isValid())
                {// Descriptor只能在该服务处于ServiceDiscovered时写入
                    mpLowEnergyService->writeDescriptor(notificationDesc, QByteArray::fromHex("0100"));
                    qDebug() << "###enable lowEnergyCharacteristic notify";

                    mpLowEnergyService->readDescriptor(notificationDesc);
                }
                QByteArray sendData;
                sendData.append("Test\r\n");
                // Characteristic只能在该服务处于ServiceDiscovered时写入。
                mpLowEnergyService->writeCharacteristic(lowEnergyCharacteristic, sendData, QLowEnergyService::WriteWithoutResponse);
                mpLowEnergyService->writeCharacteristic(lowEnergyCharacteristic, sendData, QLowEnergyService::WriteWithoutResponse);
                mpLowEnergyService->writeCharacteristic(lowEnergyCharacteristic, sendData, QLowEnergyService::WriteWithoutResponse);

            }
        }
#endif
    }
}
// /////////////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////////////
void BluetoothCtrl::lowEnergyServiceCharacteristicChanged(const QLowEnergyCharacteristic &info, const QByteArray &value)
{
    ProcessReceiveData(value);
    qDebug() << "lowEnergyServiceCharacteristicChanged:" << info.name() << "##" << info.uuid() << "   " << value;
#if 0
    // 直接发送收到数据
    if(QLowEnergyService *pLowEnergyService = qobject_cast<QLowEnergyService*>(sender()))
    {
        pLowEnergyService->writeCharacteristic(info, value, QLowEnergyService::WriteWithoutResponse);
    }
#endif
}

void BluetoothCtrl::lowEnergyServiceCharacteristicRead(const QLowEnergyCharacteristic &info, const QByteArray &value)
{
    qDebug() << "lowEnergyServiceCharacteristicRead: " << info.name() << "##" << info.uuid() << ",size:" << value.size() << ",data:" << value;
    if(QLowEnergyService *pLowEnergyService = qobject_cast<QLowEnergyService*>(sender()))
    {
        if(this->mLowEnergyModel)
        {
            this->mLowEnergyModel->updateCharacteristicValue(info.uuid().toString(), pLowEnergyService->serviceUuid().toString(),byteArrayToString(value));
        }
    }
}

void BluetoothCtrl::lowEnergyServiceCharacteristicWritten(const QLowEnergyCharacteristic &info, const QByteArray &value)
{
    qDebug() << "lowEnergyServiceCharacteristicWritten: " << info.name() << "##" << info.uuid() << "   " << value;
    emit signalSendByteLength(value.length());
    /*
    if(QLowEnergyService *pLowEnergyService = qobject_cast<QLowEnergyService*>(sender()))
    {// 读取写入的值
        pLowEnergyService->readCharacteristic(info);
    }
    */
}

void BluetoothCtrl::lowEnergyServiceDescriptorRead(const QLowEnergyDescriptor &info, const QByteArray &value)
{
    qDebug() << "lowEnergyServiceDescriptorRead: " << info.name() << "##" << info.uuid() << "   " << value;
    if(QLowEnergyService *pLowEnergyService = qobject_cast<QLowEnergyService*>(sender()))
    {
        QList<QLowEnergyCharacteristic> characteristics = pLowEnergyService->characteristics();
        for(int i = 0; i < characteristics.count(); ++i)
        {
            if(characteristics.at(i).descriptor(info.uuid()).isValid())
            {
                if(this->mLowEnergyModel)
                {
                    this->mLowEnergyModel->updateDescriptorValue(info.uuid().toString(), characteristics.at(i).uuid().toString(), pLowEnergyService->serviceUuid().toString(), byteArrayToString(value));
                }
            }
        }
    }
}

void BluetoothCtrl::lowEnergyServiceDescriptorWritten(const QLowEnergyDescriptor &info, const QByteArray &value)
{
    qDebug() << "lowEnergyServiceDescriptorWritten: " << info.name() << "##" << info.uuid() << "   " << value;
    if(QLowEnergyService *pLowEnergyService = qobject_cast<QLowEnergyService*>(sender()))
    {// 读取写入的值
        pLowEnergyService->readDescriptor(info);
    }
}

void BluetoothCtrl::lowEnergyServiceError(QLowEnergyService::ServiceError error)
{
    qDebug() << "lowEnergyServiceError: " << error;
    switch (error) {
    case QLowEnergyService::NoError:
        break;
    case QLowEnergyService::OperationError:
        emit signalBluetoothState(BluetoothState_LowEnergyServiceOperationError);
        break;
    case QLowEnergyService::CharacteristicWriteError:
        emit signalBluetoothState(BluetoothState_LowEnergyServiceCharacteristicWriteError);
        break;
    case QLowEnergyService::DescriptorWriteError:
        emit signalBluetoothState(BluetoothState_LowEnergyServiceDescriptorWriteError);
        break;
    case QLowEnergyService::UnknownError:
        emit signalBluetoothState(BluetoothState_LowEnergyServiceUnknownError);
        break;
    case QLowEnergyService::CharacteristicReadError:
        emit signalBluetoothState(BluetoothState_LowEnergyServiceCharacteristicReadError);
        break;
    case QLowEnergyService::DescriptorReadError:
        emit signalBluetoothState(BluetoothState_LowEnergyServiceDescriptorReadError);
        break;
    default:
        emit signalBluetoothState(BluetoothState_LowEnergyServiceUnknownError);
        break;
    }
}

bool BluetoothCtrl::connectLowEnergyDevice(const QString &lowEnergyDeviceAddr)
{
    qDebug() << "connectLowEnergyDevice:" << lowEnergyDeviceAddr;
    // 停止清理搜索
    stopDeviceScan();
    stopServiceScan();
    disconnectSocket();

    // 删除旧对象
    disconnectLowEnergyDevice();

    // 新建
    //mpLowEnergyCtrl = QLowEnergyController::createCentral(info);
    //mpLowEnergyCtrl = QLowEnergyController::createCentral(QBluetoothDeviceInfo(QBluetoothAddress("00:15:87:21:0F:1D"), "", 0));
    //mpLowEnergyCtrl = new QLowEnergyController(QBluetoothAddress("00:15:87:21:0F:1D"), this);
    //mpLowEnergyCtrl.reset(new QLowEnergyController(QBluetoothAddress("E8:EB:11:0A:E6:05"), this));
    mpLowEnergyCtrl.reset(new QLowEnergyController(QBluetoothAddress(lowEnergyDeviceAddr), this));
    if(mpLowEnergyCtrl)
    {
        // 绑定信号
        connect(mpLowEnergyCtrl.get(), &QLowEnergyController::connected, this, &BluetoothCtrl::lowEnergyCtrlConnected);
        connect(mpLowEnergyCtrl.get(), &QLowEnergyController::disconnected, this, &BluetoothCtrl::lowEnergyCtrlDisconnected);
        connect(mpLowEnergyCtrl.get(), &QLowEnergyController::stateChanged, this, &BluetoothCtrl::lowEnergyCtrlStateChanged);
        connect(mpLowEnergyCtrl.get(), SIGNAL(error(QLowEnergyController::Error)), this, SLOT(lowEnergyCtrlError(QLowEnergyController::Error)));

        connect(mpLowEnergyCtrl.get(), &QLowEnergyController::serviceDiscovered, this, &BluetoothCtrl::lowEnergyCtrlServiceDiscovered);
        connect(mpLowEnergyCtrl.get(), &QLowEnergyController::discoveryFinished, this, &BluetoothCtrl::lowEnergyCtrlDiscoveryFinished);
        connect(mpLowEnergyCtrl.get(), &QLowEnergyController::connectionUpdated, this, &BluetoothCtrl::lowEnergyCtrlConnectionUpdated);
        // 连接低功耗蓝牙设备
        emit signalBluetoothState(BluetoothCtrl::BluetoothState_LowEnergyConnectStart);
        mpLowEnergyCtrl->connectToDevice();
        qDebug() << "lowEnergy role:" << mpLowEnergyCtrl->role();
        return true;
    }
    else
    {
        qDebug() << "new QLowEnergyController false";
        return false;
    }
}

bool BluetoothCtrl::disconnectLowEnergyDevice()
{
    mpLowEnergyServiceSelected.reset();
    strCharacteristicUuidSelected.clear();
    mLowEnergyServiceList.clear();
    miDiscoverDetailsIndex = -1;
    if (mpLowEnergyCtrl)
    {
        if(mpLowEnergyCtrl->state() != QLowEnergyController::UnconnectedState
                && mpLowEnergyCtrl->state() != QLowEnergyController::ConnectingState)
        {
            mpLowEnergyCtrl->disconnectFromDevice();
        }
        mpLowEnergyCtrl.reset();
    }
    //mLowEnergyCharacteristicSelected = QLowEnergyCharacteristic();   // 置无效
    if(this->mLowEnergyModel)
    {
        this->mLowEnergyModel->clear();
    }

    return true;
}

bool BluetoothCtrl::selectLowEnergyCharacteristic(const QString &characteristicName, const QString &characteristicUuid, const QString &serviceName, const QString &serviceUuid)
{
    Q_UNUSED(characteristicName)
    Q_UNUSED(serviceName)
    for (int i = 0; i < mLowEnergyServiceList.length(); ++i)
    {
        if(mLowEnergyServiceList[i]->serviceUuid() == QBluetoothUuid(serviceUuid))
        {
            QLowEnergyCharacteristic lowEnergyCharacteristic = mLowEnergyServiceList[i]->characteristic(QBluetoothUuid(characteristicUuid));
            if(lowEnergyCharacteristic.isValid())
            {
                mpLowEnergyServiceSelected = mLowEnergyServiceList[i];
                strCharacteristicUuidSelected = lowEnergyCharacteristic.uuid().toString();
                return true;
            }
            else
            {
                qDebug() << "can't find characteristic:" << characteristicUuid;
            }
        }
    }
    return false;
}

bool BluetoothCtrl::readLowEnergyCharacteristic(const QString &characteristicName, const QString &characteristicUuid, const QString &serviceName, const QString &serviceUuid)
{
    Q_UNUSED(characteristicName)
    Q_UNUSED(serviceName)
    for (int i = 0; i < mLowEnergyServiceList.length(); ++i)
    {
        if(mLowEnergyServiceList[i]->serviceUuid() == QBluetoothUuid(serviceUuid))
        {
            QLowEnergyCharacteristic lowEnergyCharacteristic = mLowEnergyServiceList[i]->characteristic(QBluetoothUuid(characteristicUuid));
            if(lowEnergyCharacteristic.isValid())
            {
                mLowEnergyServiceList[i]->readCharacteristic(lowEnergyCharacteristic);
                return true;
            }
            else
            {
                qDebug() << "can't find characteristic:" << characteristicUuid;
            }
        }
    }
    return false;
}

bool BluetoothCtrl::writeLowEnergyDescriptor(const QString &descriptorName, const QString &descriptorUuid, const QString &characteristicUuid, const QString &serviceUuid, QString strData, EnumCharset charset)
{
    qDebug() << "writeLowEnergyDescriptor:" << descriptorName << "  " << descriptorUuid << "  " << characteristicUuid << "  " << serviceUuid << "  " << strData << ", charset:" << charset;
    Q_UNUSED(descriptorName)

    QByteArray byteData;// = data.toUtf8();
    if(!StringToByteArray(strData, charset, byteData))
    {
        return false;
    }
    for (int i = 0; i < mLowEnergyServiceList.length(); ++i)
    {
        if(mLowEnergyServiceList[i]->serviceUuid() == QBluetoothUuid(serviceUuid))
        {
            QLowEnergyCharacteristic lowEnergyCharacteristic = mLowEnergyServiceList[i]->characteristic(QBluetoothUuid(characteristicUuid));
            if(lowEnergyCharacteristic.isValid())
            {
                QLowEnergyDescriptor lowEnergyDescriptor = lowEnergyCharacteristic.descriptor(QBluetoothUuid(descriptorUuid));
                if(lowEnergyDescriptor.isValid())
                {
                    qDebug() << "writeDescriptor():" << strData;
                    qDebug() << "writeDescriptor()QByteArray:" << byteData;
                    mLowEnergyServiceList[i]->writeDescriptor(lowEnergyDescriptor, byteData);
                    return true;
                }
                else
                {
                    qDebug() << "can't find descriptor:" << descriptorUuid;
                }
            }
            else
            {
                qDebug() << "can't find characteristic:" << characteristicUuid;
            }
        }
    }
    return false;
}

bool BluetoothCtrl::readLowEnergyDescriptor(const QString &descriptorName, const QString &descriptorUuid, const QString &characteristicUuid, const QString &serviceUuid)
{
    qDebug() << "readLowEnergyDescriptor:" << descriptorName << "  " << descriptorUuid << "  " << characteristicUuid << "  " << serviceUuid;
    Q_UNUSED(descriptorName)
    for (int i = 0; i < mLowEnergyServiceList.length(); ++i)
    {
        if(mLowEnergyServiceList[i]->serviceUuid() == QBluetoothUuid(serviceUuid))
        {
            QLowEnergyCharacteristic lowEnergyCharacteristic = mLowEnergyServiceList[i]->characteristic(QBluetoothUuid(characteristicUuid));
            if(lowEnergyCharacteristic.isValid())
            {
                QLowEnergyDescriptor lowEnergyDescriptor = lowEnergyCharacteristic.descriptor(QBluetoothUuid(descriptorUuid));
                if(lowEnergyDescriptor.isValid())
                {
                    mLowEnergyServiceList[i]->readDescriptor(lowEnergyDescriptor);
                    return true;
                }
                else
                {
                    qDebug() << "can't find descriptor:" << descriptorUuid;
                }
            }
            else
            {
                qDebug() << "can't find characteristic:" << characteristicUuid;
            }
        }
    }
    return false;
}

// /////////////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////////////
bool BluetoothCtrl::startScan()
{
    if(this->mDeviceModel)
    {
        this->mDeviceModel->clear();
    }
    if(this->mLowEnergyModel)
    {
        this->mLowEnergyModel->clear();
    }
    disconnectLowEnergyDevice();
    disconnectSocket();
    stopServiceScan();
    stopDeviceScan();

#if 1
    // 设备查找
    if(!startDeviceScan())
    {
        return false;
    }
    return true;
#endif

#if 0
    // 服务查找
    //mServiceDiscoveryAgent.setRemoteAddress(QBluetoothAddress("00:15:87:21:0F:1D"));
    mServiceDiscoveryAgent.setRemoteAddress(QBluetoothAddress("20:18:08:30:41:20"));
    StartServiceScan();
    return true;
#endif


#if 0
    // 低功耗蓝牙
    //if(info.address().toString() != "00:15:87:21:0F:1D")
    {
        //mDeviceDiscoveryAgent.stop();
        //if("00:15:87:21:0F:1D" == info.address().toString())
        {
            // 连接低功耗设备
            if (mpLowEnergyCtrl)
            {
                mpLowEnergyCtrl->disconnectFromDevice();
                mpLowEnergyCtrl.reset();
                //delete mpLowEnergyCtrl;
                //mpLowEnergyCtrl = nullptr;
            }
            // 新建
            //mpLowEnergyCtrl = QLowEnergyController::createCentral(info);
            //mpLowEnergyCtrl = QLowEnergyController::createCentral(QBluetoothDeviceInfo(QBluetoothAddress("00:15:87:21:0F:1D"), "", 0));
            mpLowEnergyCtrl.reset(new QLowEnergyController(QBluetoothAddress("00:15:87:21:0F:1D"), this));
            //mpLowEnergyCtrl.reset(new QLowEnergyController(QBluetoothAddress("E8:EB:11:0A:E6:05"), this));
            if(mpLowEnergyCtrl)
            {
                // 绑定信号
                connect(mpLowEnergyCtrl.get(), &QLowEnergyController::connected, this, &BluetoothCtrl::lowEnergyCtrlConnected);
                connect(mpLowEnergyCtrl.get(), &QLowEnergyController::disconnected, this, &BluetoothCtrl::lowEnergyCtrlDisconnected);
                connect(mpLowEnergyCtrl.get(), &QLowEnergyController::stateChanged, this, &BluetoothCtrl::lowEnergyCtrlStateChanged);
                connect(mpLowEnergyCtrl.get(), SIGNAL(error(QLowEnergyController::Error)), this, SLOT(lowEnergyCtrlError(QLowEnergyController::Error)));

                connect(mpLowEnergyCtrl.get(), &QLowEnergyController::serviceDiscovered, this, &BluetoothCtrl::lowEnergyCtrlServiceDiscovered);
                connect(mpLowEnergyCtrl.get(), &QLowEnergyController::discoveryFinished, this, &BluetoothCtrl::lowEnergyCtrlDiscoveryFinished);
                connect(mpLowEnergyCtrl.get(), &QLowEnergyController::connectionUpdated, this, &BluetoothCtrl::lowEnergyCtrlConnectionUpdated);
                // 连接低功耗蓝牙设备
                mpLowEnergyCtrl->connectToDevice();
                qDebug() << "role:" << mpLowEnergyCtrl->role();
            }
            else
            {
                qDebug() << "new QLowEnergyController false";
            }
        }
        return true;
    }
#endif
}

bool BluetoothCtrl::sendData(QString data, EnumCharset charset)
{
    QByteArray byteData;// = data.toUtf8();
    if(!StringToByteArray(data, charset, byteData))
    {
        return false;
    }
    bool bRes = false;
    if(mpBluetoothSocket)
    {
        if(QBluetoothSocket::ConnectedState == this->mpBluetoothSocket->state())
        {
            if(this->mpBluetoothSocket->write(byteData) != byteData.length())
            {
                qDebug() << "QBluetoothSocket write failed";
            }
            else
            {
                bRes = true;
            }
        }
    }
    if(mpLowEnergyCtrl && mpLowEnergyServiceSelected && !strCharacteristicUuidSelected.isEmpty())
    {
        QBluetoothUuid characteristicUuidSelected(strCharacteristicUuidSelected);
        if(!characteristicUuidSelected.isNull())
        {
            QLowEnergyCharacteristic lowEnergyCharacteristic = mpLowEnergyServiceSelected->characteristic(characteristicUuidSelected);
            if(lowEnergyCharacteristic.isValid())
            {
                for (int i = 0; i < byteData.count();)
                {
                    // 有个默认发送长度限制，限制20个字节，暂时没找到地方修改
                    QByteArray sendData = byteData.mid(i, 20);
                    i += sendData.count();
                    mpLowEnergyServiceSelected->writeCharacteristic(lowEnergyCharacteristic, sendData, QLowEnergyService::WriteWithoutResponse);
                }
                bRes = true;
            }
            else {
                qDebug() << "can't find characteristic:" << strCharacteristicUuidSelected;
            }
        }
        else {
            qDebug() << "strCharacteristicUuidSelected invalid:" << strCharacteristicUuidSelected;
        }
    }

    return bRes;
}

void BluetoothCtrl::setReceiveCharsetType(BluetoothCtrl::EnumCharset charset)
{
    mRxCharset = charset;
}

void BluetoothCtrl::ProcessReceiveData(const QByteArray& rxData)
{
    //emit signalReceiveData(byteArrayToString(rxData));
    emit signalReceiveData(rxData);
    emit signalReceiveByteLength(rxData.length());
    QString strRxData;
    switch (mRxCharset)
    {
    case BluetoothCtrl::EnumCharset_HEX:
        strRxData = QString::fromUtf8(rxData.toHex(' '));
        break;
    case BluetoothCtrl::EnumCharset_GBK:{
        static QTextCodec * codec = QTextCodec::codecForName("GB18030");
        if(!codec)
        {
            qDebug() << "GB18030 TextCodec create failed";
            return;
        }
        static QTextDecoder * decoder = codec->makeDecoder();
        if(!decoder)
        {
            qDebug() << "GB18030 TextDecoder create failed";
            return;
        }
        strRxData = decoder->toUnicode(rxData);
    } break;
    case BluetoothCtrl::EnumCharset_UTF8:{
        static QTextCodec * codec = QTextCodec::codecForName("UTF-8");
        if(!codec)
        {
            qDebug() << "UTF-8 TextCodec create failed";
            return;
        }
        static QTextDecoder * decoder = codec->makeDecoder();
        if(!decoder)
        {
            qDebug() << "UTF-8 TextDecoder create failed";
            return;
        }
        strRxData = decoder->toUnicode(rxData);
    } break;
    case BluetoothCtrl::EnumCharset_UNICODE:{
        static QTextCodec * codec = QTextCodec::codecForName("UTF-16");
        if(!codec)
        {
            qDebug() << "UTF-16 TextCodec create failed";
            return;
        }
        static QTextDecoder * decoder = codec->makeDecoder();
        if(!decoder)
        {
            qDebug() << "UTF-16 TextDecoder create failed";
            return;
        }
        strRxData = decoder->toUnicode(rxData);
    } break;
    }
    emit signalReceiveString(strRxData);
}

void BluetoothCtrl::setBluetoothDeviceModel(BluetoothDeviceModel *model)
{
    this->mDeviceModel = model;
}

void BluetoothCtrl::setLowEnergyInfoModel(LowEnergyInfoModel *model)
{
    this->mLowEnergyModel = model;
}




